#include "door_common.h"
#include "gkt_io_debounce.h"

#if defined(GKT_CONFIG_DOOR_TAMPER_ENABLE) && GKT_CONFIG_DOOR_TAMPER_ENABLE	\
	&& defined(GKT_CONFIG_DOOR_TAMPER0_GPIO_PIN)	\
	&& defined(GKT_CONFIG_DOOR_TAMPER_GPIO_PIN_NUMS) \
	&& (GKT_CONFIG_DOOR_TAMPER_GPIO_PIN_NUMS == 1)

typedef struct _door_tamper {
	uint32_t	io_debounce_state;
	int	detect;
} door_tamper_s;
static door_tamper_s s_door_tamper;

void gkt_door_tamper_stop(void)
{
	s_door_tamper.io_debounce_state &= ~DOOR_TAMPER_IO_DEBOUNCE_BUSY;
	door_inner_notify(GKT_DOOR_NOTIFY_TAMPER, 0);
}

static void door_tamper_debounce_complete(int result, int detect)
{
	gkt_info("door_tamper_debounce_complete: result(%d)\n", result);

	if (s_door_tamper.io_debounce_state  & DOOR_TAMPER_IO_DEBOUNCE_BUSY) {
		s_door_tamper.io_debounce_state &= ~DOOR_TAMPER_IO_DEBOUNCE_BUSY;
		if (GKT_IO_DEBOUNCE_OK == result)
			door_inner_notify(GKT_DOOR_NOTIFY_TAMPER, s_door_tamper.detect);
		else
			s_door_tamper.detect = !s_door_tamper.detect;
	}
}

static void door_tamper_notify(int detect)
{
	int retval;
	
	gkt_info("door_tamper_notify: detect(%d) state=%d\n", detect, s_door_tamper.io_debounce_state);
	if (s_door_tamper.io_debounce_state & DOOR_TAMPER_IO_DEBOUNCE_READY) {
		if ((detect == s_door_tamper.detect)
			&& s_door_tamper.io_debounce_state & DOOR_TAMPER_IO_DEBOUNCE_BUSY)
		{
			return;
		}

		s_door_tamper.io_debounce_state &= ~DOOR_TAMPER_IO_DEBOUNCE_BUSY;
		s_door_tamper.detect = detect;

		retval = gkt_io_debounce_start(GKT_IO_DEBOUNCE_ID(door_tamper), detect, 0);
		if (GKT_SUCCESS == retval) {
			s_door_tamper.io_debounce_state |= DOOR_TAMPER_IO_DEBOUNCE_BUSY;
			return;
		}
	}

	s_door_tamper.detect = detect;
	door_inner_notify(GKT_DOOR_NOTIFY_TAMPER, detect);
}

static void door_tamper_detect_notify(uint32_t pin)
{
	gkt_unused(pin);
	door_tamper_notify(0);
}

static void door_tamper_undetect_notify(uint32_t pin)
{
	gkt_unused(pin);
	door_tamper_notify(1);
}

static __RETMEM_USR uint32_t s_door_tamper_detect_level;
#ifndef GKT_CONFIG_DOOR_TAMPER_DETECT_LEVEL
static const uint32_t sc_door_tamper_gpio_flags[2] = {
	GKT_GPIO_F_INPUT | GKT_GPIO_F_INT_EDGE_RAISE 
	| GKT_GPIO_F_INT_DEBOUNCE | GKT_GPIO_F_INT_MASKED,
	GKT_GPIO_F_INPUT | GKT_GPIO_F_INT_EDGE_FALL 
	| GKT_GPIO_F_INT_DEBOUNCE | GKT_GPIO_F_INT_MASKED,
};
int door_tamper_init(void)
{
	gkt_io_debounce_attr_s io_debounce_attr;
	uint32_t detect_check_times;
	int retval;

	io_debounce_attr.step_ms = 0;	/* use default settings */
	io_debounce_attr.detect_fn = gkt_door_tamper_is_detected;
	io_debounce_attr.complete_fn = door_tamper_debounce_complete;
	retval = gkt_io_debounce_config(GKT_IO_DEBOUNCE_ID(door_tamper),
				&io_debounce_attr);
	if (GKT_SUCCESS == retval)
		s_door_tamper.io_debounce_state = DOOR_TAMPER_IO_DEBOUNCE_READY;
	else
		gkt_error("door_tamper: debounce config failed!\n");

	if (g_system_info.reset_mode != GKT_SYSTEM_RESET_WAKEUP) {
		retval = gkt_gpio_config(GKT_CONFIG_DOOR_TAMPER0_GPIO_PIN,
						GKT_GPIO_F_INPUT, NULL);
		if (retval != GKT_SUCCESS) {
			gkt_error("door_tamper_init: <0> config gpio failed %d\n", retval);
			return retval;
		}

		gkt_gpio_get_pin_level(GKT_CONFIG_DOOR_TAMPER0_GPIO_PIN, 
				&s_door_tamper_detect_level);
		s_door_tamper_detect_level ^= 1;
		gkt_info("door_tamper_init: detect_level - %u\n",
				s_door_tamper_detect_level);
	}

	retval = gkt_gpio_config(GKT_CONFIG_DOOR_TAMPER0_GPIO_PIN,
					sc_door_tamper_gpio_flags[s_door_tamper_detect_level], 
					door_tamper_undetect_notify);
	if (retval != GKT_SUCCESS) {
		gkt_error("door_tamper_init: <1> config gpio failed %d\n", retval);
		return retval;
	}

	if (GKT_SYSTEM_RESET_HARD != g_system_info.reset_mode) {
		detect_check_times = DOOR_TAMPER_WAKEUP_CHECK_TIMES;
		do {
			s_door_tamper.detect = gkt_door_tamper_is_detected();
			if (!s_door_tamper.detect)
				goto done;
			gkt_delay_us(DOOR_TAMPER_WAKEUP_CHECK_UNIT_US);
		} while (--detect_check_times > 0);

		gkt_info("door_tamper_init: *** WAKEUP ***\n");
		gkt_wakeup_set_source(GKT_WAKEUP_SRC_door_tamper);
	}

done:
	gkt_gpio_interrupt_unmask(GKT_CONFIG_DOOR_TAMPER0_GPIO_PIN);
	return GKT_SUCCESS;
}

#else
#if (0 == GKT_CONFIG_DOOR_TAMPER_DETECT_LEVEL)
#define DOOR_TAMPER_GPIO_FLAGS	\
	(GKT_GPIO_F_INPUT | GKT_GPIO_F_INT_EDGE_FALL\
		| GKT_GPIO_F_INT_DEBOUNCE | GKT_GPIO_F_INT_MASKED)
#else
#define DOOR_TAMPER_GPIO_FLAGS	\
	(GKT_GPIO_F_INPUT | GKT_GPIO_F_INT_EDGE_RAISE\
		| GKT_GPIO_F_INT_DEBOUNCE | GKT_GPIO_F_INT_MASKED)
#endif

/************************************************************
* BPK Key:A total of 32 Uint32_t 
*		  uint32_t [0]:description:gkt_retmem.h
*         uint32_t [1]:			   
*			   Byte[0]:door tamper used 
					--io1  :door tamper detect level
*			   		--io1~2:door tamper gpio io number
*              Byte[1]:door lock used
					Record door lock status		 
************************************************************/
int door_tamper_init(void)
{
	gkt_io_debounce_attr_s io_debounce_attr;
	uint32_t value, detect_check_times;
	int retval;

	io_debounce_attr.detect_fn = gkt_door_tamper_is_detected;
	io_debounce_attr.complete_fn = door_tamper_debounce_complete;
	retval = gkt_io_debounce_config(GKT_IO_DEBOUNCE_ID(door_tamper),
				&io_debounce_attr);
	if (GKT_SUCCESS == retval)
		s_door_tamper.io_debounce_state = DOOR_TAMPER_IO_DEBOUNCE_READY;
	else
		gkt_error("door_tamper: debounce config failed!\n");

	retval = gkt_gpio_config(GKT_CONFIG_DOOR_TAMPER0_GPIO_PIN,
					DOOR_TAMPER_GPIO_FLAGS, 
					door_tamper_undetect_notify);
	if (retval != GKT_SUCCESS) {
		gkt_error("door_tamper_init: <1> config gpio failed %d\n", retval);
		return retval;
	}
	
	G_BPK_ReadKey(&value, 1, GKT_RETMEM_DOOR_RELATE);
	if (GKT_SYSTEM_RESET_HARD == g_system_info.reset_mode) {
		gkt_gpio_get_pin_level(GKT_CONFIG_DOOR_TAMPER0_GPIO_PIN, 
				&s_door_tamper_detect_level);
		gkt_info("door_tamper_init: detect_level - %u\n",
				s_door_tamper_detect_level);

		value &= 0xFFFFFF00;
		value |= s_door_tamper_detect_level;
		G_BPK_WriteKey(&value, 1, GKT_RETMEM_DOOR_RELATE);
	}	
	else {
		s_door_tamper_detect_level = (value & 0xff);
	}
	
	if (GKT_SYSTEM_RESET_WAKEUP == g_system_info.reset_mode) {
		detect_check_times = DOOR_TAMPER_WAKEUP_CHECK_TIMES;
		do {
			s_door_tamper.detect = gkt_door_tamper_is_detected();		
			if ((!s_door_tamper.detect) || (s_door_tamper_detect_level == GKT_CONFIG_DOOR_TAMPER_DETECT_LEVEL))
				goto done;
			
			gkt_delay_us(DOOR_TAMPER_WAKEUP_CHECK_UNIT_US);
		} while (--detect_check_times > 0);

		gkt_info("door_tamper_init: *** WAKEUP ***\n");
		gkt_wakeup_set_source(GKT_WAKEUP_SRC_door_tamper);
	}

done:
	gkt_gpio_interrupt_unmask(GKT_CONFIG_DOOR_TAMPER0_GPIO_PIN);
	return GKT_SUCCESS;
}

uint32_t gkt_door_tamper_standby(uint32_t *door_tamper_num)
{
	uint32_t value, level=GKT_CONFIG_DOOR_TAMPER_DETECT_LEVEL;
	int retval;

	retval = gkt_gpio_get_pin_level(GKT_CONFIG_DOOR_TAMPER0_GPIO_PIN, &level);
	gkt_printf("gkt_door_tamper level=%d\n", level);
	if ((retval == GKT_SUCCESS) && (level != s_door_tamper_detect_level)) {
		G_BPK_ReadKey(&value, 1, GKT_RETMEM_DOOR_RELATE);
		value &= 0xFFFFFF00;
		value |= level;
		G_BPK_WriteKey(&value, 1, GKT_RETMEM_DOOR_RELATE);
	}
	
	return (level == GKT_CONFIG_DOOR_TAMPER_DETECT_LEVEL) ? 0 : 1;
}
#endif

int gkt_door_tamper_is_detected(void)
{
	uint32_t level;
	int retval;

	retval = gkt_gpio_get_pin_level(GKT_CONFIG_DOOR_TAMPER0_GPIO_PIN, &level);
	gkt_info("gkt_door_tamper detect level=%d\n", level);

	return ((GKT_SUCCESS == retval) 
			&& (DOOR_TAMPER_DETECT_LEVEL == level)) ? 1 : 0;
}

int gkt_door_tamper_init(void)
{
	gkt_io_debounce_attr_s io_debounce_attr;
	int retval;
	uint32_t value;

	io_debounce_attr.detect_fn = gkt_door_tamper_is_detected;
	io_debounce_attr.complete_fn = door_tamper_debounce_complete;
	retval = gkt_io_debounce_config(GKT_IO_DEBOUNCE_ID(door_tamper),
				&io_debounce_attr);
	if (GKT_SUCCESS == retval)
		s_door_tamper.io_debounce_state = DOOR_TAMPER_IO_DEBOUNCE_READY;
	else
		gkt_error("door_tamper: debounce config failed!\n");

	retval = gkt_gpio_config(GKT_CONFIG_DOOR_TAMPER0_GPIO_PIN,
						DOOR_TAMPER_GPIO_FLAGS, door_tamper_detect_notify);
	if (retval != GKT_SUCCESS) {
		gkt_error("door_tamper_init: <0> config gpio failed %d\n", retval);
		return retval;
	}
	gkt_door_tamper_is_detected();//test add 

#if defined(GKT_CONFIG_DOOR_TAMPER_DETECT_LEVEL)
	if (GKT_SYSTEM_RESET_HARD == g_system_info.reset_mode) {
		gkt_gpio_get_pin_level(GKT_CONFIG_DOOR_TAMPER0_GPIO_PIN,
				&s_door_tamper_detect_level);	
		gkt_info("door_tamper_init: detect_level - %u\n",
				s_door_tamper_detect_level);

		G_BPK_ReadKey(&value, 1, GKT_RETMEM_DOOR_RELATE);
		value &= 0xFFFFFF00;
		value |= s_door_tamper_detect_level;
		G_BPK_WriteKey(&value, 1, GKT_RETMEM_DOOR_RELATE);	
	}
#else
	if (GKT_SYSTEM_RESET_HARD == g_system_info.reset_mode) {
		gkt_gpio_get_pin_level(GKT_CONFIG_DOOR_TAMPER0_GPIO_PIN,
				&s_door_tamper_detect_level);
		s_door_tamper_detect_level ^= 1;
		gkt_info("door_tamper_init: detect_level - %u\n",
				s_door_tamper_detect_level);
	}
#endif
	gkt_gpio_interrupt_unmask(GKT_CONFIG_DOOR_TAMPER0_GPIO_PIN);

	return retval;
}

int gkt_door_tamper_standby_input(void)
{
	int retval;
		
	retval = gkt_gpio_config(GKT_CONFIG_DOOR_TAMPER0_GPIO_PIN,
					GKT_GPIO_F_INPUT, NULL);
	if (retval != GKT_SUCCESS) 
		gkt_error("door_tamper_standby_input: config tamper0 failed %d\n", retval);
	
	return retval;
}

#endif

